import threading
import time
from queue import Queue


# 实现了一个支持按ID过滤获取元素的高级线程安全队列 FilterableQueue，是对 Python 标准库 Queue 的扩展。
class FilterableQueue(Queue):
    def __init__(self, maxsize: int = 0) -> None:
        super().__init__(maxsize)
        #新增条件变量 self.updated：
        #绑定到队列的互斥锁 self.mutex（继承自父类）
        #实现 细粒度状态通知（比父类仅有的 not_empty 更灵活）
        self.updated = threading.Condition(self.mutex)

    def get_by_id(self, target_id, id_function, timeout):
        # id_function 动态ID提取器，允许自定义ID提取逻辑
        start_time = time.time()
        item = None
        found = False
        while time.time() - start_time < timeout:# 超时控制
            with self.not_empty:# 进入队列锁
                if not self.queue:
                    self.not_empty.wait(timeout)# 等待队列非空
                item = self.queue[0]        # 查看队首元素
                item_id = id_function(item) # 提取ID
                if item_id == target_id:    # ID匹配
                    item = self.queue.popleft()# 弹出元素
                    found = True
                    self.updated.notify_all()# 通知所有等待线程
                    break
                else:# ID不匹配，等待队列状态变化，再次检查
                    self.updated.wait(timeout)
        if not found:
            raise RuntimeError(f'Getting from FilterableQueue timed out after {timeout} seconds.')
        return item

import threading
filterable_queue = FilterableQueue()

def get_id(item):
    return item

def task1():
    for i in range(9):
        # 找 0~8 的元素
        target = filterable_queue.get_by_id(i, get_id, 10)
        print("get ", target)

def task2():
    # 找 id=9的 元素
    result = filterable_queue.get_by_id(9, get_id, 10)
    assert result==9
    print("get ", result)

def put_items():
    for i in range(10):
        # 逐个入队 0-9
        filterable_queue.put(i)
        print("put ", i)

thread1 = threading.Thread(target=task1)
thread2 = threading.Thread(target=task2)
thread3 = threading.Thread(target=put_items)
thread1.start()
thread2.start()
thread3.start()
thread1.join()
thread2.join()
thread3.join()